#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include <QFile>

template<typename T>
std::vector<float> convertToFloat(const QByteArray &data)
{
    qInfo() << "convertToFloat" << data.size();
    std::vector<float> result;
    const T *samples = reinterpret_cast<const T*>(data.constData());
    int sampleCount = data.size() / sizeof(T);

    result.reserve(sampleCount);
    T maxValue = std::numeric_limits<T>::max();
    for (int i = 0; i < sampleCount; ++i) {

        result.push_back(static_cast<float>(samples[i]) / maxValue);
    }

    return result;
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    std::string whisper_model_path = WHISPER_MODEL_PATH;
    std::string sample_path        = "C:/Users/yubo/Desktop/111.wav";

    // Load the sample audio file
    std::vector<float> pcmf32;
    std::vector<std::vector<float>> pcmf32s;
    // assert(read_audio_data(sample_path, pcmf32, pcmf32s, false));
    // qInfo() << "pcmf32" << pcmf32.size();
    QFile file(QString::fromStdString(sample_path));
    file.open(QFile::ReadOnly);
    pcmf32 = convertToFloat<int16_t>(file.readAll());

    struct whisper_context_params cparams = whisper_context_default_params();
    wctx = whisper_init_from_file_with_params(
        whisper_model_path.c_str(),
        cparams);

    recognition(pcmf32);

    initializeAudio(QAudioDeviceInfo::defaultInputDevice());
    connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::toggleMode);
    connect(ui->pushButton_2, &QPushButton::clicked, this,[this](){
        stopRecording();
        recognition(convertToFloat<int16_t>(audioData));
    });

    // m_pAudioRecorderWithProbe = new AudioRecorderWithProbe(this);
    // connect(ui->pushButton, &QPushButton::clicked, m_pAudioRecorderWithProbe,&AudioRecorderWithProbe::startRecording);
    // connect(ui->pushButton_2, &QPushButton::clicked, m_pAudioRecorderWithProbe,[this](){
    //     m_pAudioRecorderWithProbe->stop();
    //     recognition(convertToFloat<int16_t>(m_pAudioRecorderWithProbe->audiodata));
    // });
    // connect(ui->pushButton_3, &QPushButton::clicked, m_pAudioRecorderWithProbe,&AudioRecorderWithProbe::setFile);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::recognition(std::vector<float> pcmf32)
{
    qInfo() << "recognition" << pcmf32.size();
    if (pcmf32.empty())
        return;
    std::string vad_model_path     = VAD_MODEL_PATH;
    struct whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_BEAM_SEARCH);
    wparams.vad            = true;
    wparams.vad_model_path = vad_model_path.c_str();

    wparams.vad_params.threshold               = 0.5f;
    wparams.vad_params.min_speech_duration_ms  = 250;
    wparams.vad_params.min_silence_duration_ms = 100;
    wparams.vad_params.max_speech_duration_s   = FLT_MAX;
    wparams.vad_params.speech_pad_ms           = 30;
    wparams.language = "auto";
    wparams.translate = false;
    assert(whisper_full_parallel(wctx, wparams, pcmf32.data(), pcmf32.size(), 1) == 0);
    QString transcribedText;
    int segments = whisper_full_n_segments(wctx);

    for (int i = 0; i < segments; ++i) {
        const char *text = whisper_full_get_segment_text(wctx, i);
        transcribedText += QString::fromUtf8(text);
    }
    qInfo() << transcribedText;
}

void MainWindow::initializeAudio(const QAudioDeviceInfo &deviceInfo)
{
    QAudioFormat format;
    format.setSampleRate(8000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setSampleType(QAudioFormat::SignedInt);
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setCodec("audio/pcm");

    if (!deviceInfo.isFormatSupported(format)) {
        qWarning() << "Default format not supported - trying to use nearest";
        format = deviceInfo.nearestFormat(format);
    }

    // m_audioInfo.reset(new AudioInfo(format));

    m_audioInput.reset(new QAudioInput(deviceInfo, format));
    // m_audioInfo->start();
    buffer.setBuffer(&audioData);
}

void MainWindow::toggleMode()
{
    // m_audioInput->start(m_audioInfo.data());
    audioData.clear();
    buffer.open(QIODevice::WriteOnly);
    m_audioInput->start(&buffer);
}

void MainWindow::stopRecording()
{
    if (m_audioInput && m_audioInput->state() != QAudio::StoppedState) {
        m_audioInput->stop();
        buffer.close();
        // // 将缓冲数据写入文件
        // QFile file(filename);
        // if (file.open(QIODevice::WriteOnly)) {
        //     file.write(audioData);
        //     file.close();
        //     qDebug() << "音频数据已保存到文件，大小:" << audioData.size() << "字节";
        // }
        // qDebug() << "停止录制音频";
    }
}

#include <stdlib.h>
#include <math.h>

#include <QDateTime>
#include <QDebug>
#include <QPainter>
#include <QVBoxLayout>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <qendian.h>

AudioInfo::AudioInfo(const QAudioFormat &format)
    : m_format(format)
{
    switch (m_format.sampleSize()) {
    case 8:
        switch (m_format.sampleType()) {
        case QAudioFormat::UnSignedInt:
            m_maxAmplitude = 255;
            break;
        case QAudioFormat::SignedInt:
            m_maxAmplitude = 127;
            break;
        default:
            break;
        }
        break;
    case 16:
        switch (m_format.sampleType()) {
        case QAudioFormat::UnSignedInt:
            m_maxAmplitude = 65535;
            break;
        case QAudioFormat::SignedInt:
            m_maxAmplitude = 32767;
            break;
        default:
            break;
        }
        break;

    case 32:
        switch (m_format.sampleType()) {
        case QAudioFormat::UnSignedInt:
            m_maxAmplitude = 0xffffffff;
            break;
        case QAudioFormat::SignedInt:
            m_maxAmplitude = 0x7fffffff;
            break;
        case QAudioFormat::Float:
            m_maxAmplitude = 0x7fffffff; // Kind of
        default:
            break;
        }
        break;

    default:
        break;
    }
}

void AudioInfo::start()
{
    open(QIODevice::WriteOnly);
}

void AudioInfo::stop()
{
    close();
}

qint64 AudioInfo::readData(char *data, qint64 maxlen)
{
    Q_UNUSED(data)
    Q_UNUSED(maxlen)

    return 0;
}

qint64 AudioInfo::writeData(const char *data, qint64 len)
{
    if (m_maxAmplitude) {
        Q_ASSERT(m_format.sampleSize() % 8 == 0);
        const int channelBytes = m_format.sampleSize() / 8;
        const int sampleBytes = m_format.channelCount() * channelBytes;
        Q_ASSERT(len % sampleBytes == 0);
        const int numSamples = len / sampleBytes;

        quint32 maxValue = 0;
        const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data);

        for (int i = 0; i < numSamples; ++i) {
            for (int j = 0; j < m_format.channelCount(); ++j) {
                quint32 value = 0;

                if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
                    value = *reinterpret_cast<const quint8*>(ptr);
                } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) {
                    value = qAbs(*reinterpret_cast<const qint8*>(ptr));
                } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
                    if (m_format.byteOrder() == QAudioFormat::LittleEndian)
                        value = qFromLittleEndian<quint16>(ptr);
                    else
                        value = qFromBigEndian<quint16>(ptr);
                } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) {
                    if (m_format.byteOrder() == QAudioFormat::LittleEndian)
                        value = qAbs(qFromLittleEndian<qint16>(ptr));
                    else
                        value = qAbs(qFromBigEndian<qint16>(ptr));
                } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
                    if (m_format.byteOrder() == QAudioFormat::LittleEndian)
                        value = qFromLittleEndian<quint32>(ptr);
                    else
                        value = qFromBigEndian<quint32>(ptr);
                } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::SignedInt) {
                    if (m_format.byteOrder() == QAudioFormat::LittleEndian)
                        value = qAbs(qFromLittleEndian<qint32>(ptr));
                    else
                        value = qAbs(qFromBigEndian<qint32>(ptr));
                } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::Float) {
                    value = qAbs(*reinterpret_cast<const float*>(ptr) * 0x7fffffff); // assumes 0-1.0
                }

                maxValue = qMax(value, maxValue);
                ptr += channelBytes;
            }
        }

        maxValue = qMin(maxValue, m_maxAmplitude);
        m_level = qreal(maxValue) / m_maxAmplitude;
    }

    array.append(QByteArray(data, len));
    emit update();
    return len;
}

